#include "framework.h"
#include "main_service.h"
#include "timer/time_wheel.h"
#include "util/config.h"
#include "handler.h"
#include "session.h"
#include "pipe_module.h"
#include "server.h"
#include "ts.h"
#include "util/time.hpp"
#include "log/log.h"
#include "config.h"

void CFrameWork::CreateInstances() {
	CClientHandler::CreateInstance();
	CServerMgr::CreateInstance();
	CPipeModule::CreateInstance();
	CNowTime::CreateInstance();
	CServerMgr::CreateInstance();
	CDBServerHandler::CreateInstance();
	CGameServerHandler::CreateInstance();
	CCliSessionFactory::CreateInstance();
	CConfigMgr::CreateInstance();
}

bool CFrameWork::Init(const char* path) {
	// initialize log module.
	if (!this->initLog(path)) {
		return false;
	}

	// load config.
	if (!CConfigMgr::instance()->Load(path)) {
		return false;
	}

	// initialize tcp net handler.
	CClientHandler::Instance()->Init();

	// initialize pipe module.
	{
		auto pipePath = std::string(path) + "/pipe.xml";
		if (!CPipeModule::Instance()->Init(pipePath.c_str(), CServerMgr::instance())) {
			LogCrit("initialize pipe with %s path error", pipePath.c_str());
			return false;
		}
		LogInfo("initialize %s pipe module ok.", pipePath.c_str());
	}

	// start listening for client.
	{
		char addr[1024] = { 0 };
		const auto ip = CConfigMgr::instance()->getIP();
		const auto port = CConfigMgr::instance()->getPort();
		const auto threadSize = CConfigMgr::instance()->getThreadSize();
		std::snprintf(addr, sizeof(addr) - 1, "%s:%d", ip.c_str(), port);
		if (!m_listener.Start(addr, threadSize)) {
			LogCrit("initialize listener on %s error", addr);
			return false;
		}
		LogInfo("initialize tcp listener on %s ok.", addr);
	}

	// log out.
	LogInfo("server is initialized ok.");

	return true;
}

void CFrameWork::Run(int count) {
	const int MIN_SLEEP_US = 1000;
	const int TIMEOUT_VALUE = 20;
	long long lastTime = GetNowMSTime();
	for (; !this->isSignaled();) {
		auto loopStart = GetNowMSTime();
		CNowTime::instance()->SetNowTime(loopStart);

		// deltaTime.
		long long deltaTime = loopStart - lastTime;

		// Timer update
		STimeWheelSpace::CTimeWheel::instance().update(deltaTime);

		// Pipe update.
		bool didWork = CPipeModule::instance()->Run(static_cast<int>(deltaTime));

		// Sleep for a while: MIN_SLEEP_US ms
		if (!didWork) {
			std::this_thread::yield();
			std::this_thread::sleep_for(std::chrono::microseconds(MIN_SLEEP_US));
		}

		// Save last time.
		lastTime = loopStart;

		// Detail log for time out.
		if (deltaTime >= TIMEOUT_VALUE) {
			LogAInfo("Run time out:%d", deltaTime);
		}
	}
}

void CFrameWork::Release() {
	// stop net.
	m_listener.Stop();

	// log out.
	LogCrit("server is exit.");
}

bool CFrameWork::initLog(const char* path) {
	anet::utils::CConfig reader;
	if (!reader.Parse((std::string(path) + "/log.conf").c_str())) {
		std::cerr << "load " << "./log.conf" << " error:" << reader.GetLastError() << std::endl;
		return false;
	}

	// log config information.
	auto logLevel = reader.GetNode<int>("log/log_level", 0);
	auto logPath = reader.GetNode<std::string>("log/log_path", "./log");
	auto logInterval = reader.GetNode<int>("log/log_interval", 1000);
	auto logName = reader.GetNode<std::string>("log/log_name", "");

	// initialize the log module
	if (auto ret = anet::log::initLog(logPath, logName, anet::log::eLogLevel(logLevel), logInterval); !ret) {
		std::cerr << "initialize log error" << std::endl;
		return false;
	}
	return true;
}
